/**
 * 
 */
package com.ws.framework.remoteservice.core.protocal;

import java.net.BindException;
import java.util.logging.Logger;

import com.ws.framework.remoteservice.core.model.ProviderInfo;
import com.ws.framework.remoteservice.core.util.NetUtils;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;

/**
 * @author WSH
 *
 */
public class Transport {
	
	private static final Logger logger = Logger.getLogger(Transport.class.getName());

	private static final NioEventLoopGroup bossGroup = new NioEventLoopGroup();
	private static final NioEventLoopGroup workerGroup = new NioEventLoopGroup();
	private static final String schemal = "TCP";

	public final static Transport instance = new Transport();

	private Transport() {
	}

	public ProviderInfo start() {
		int port = 8888;
		ServerBootstrap serverBootstrap = new ServerBootstrap();
		serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
				.option(ChannelOption.SO_BACKLOG, 20000).option(ChannelOption.TCP_NODELAY, true)
				.childOption(ChannelOption.TCP_NODELAY, true).childOption(ChannelOption.SO_REUSEADDR, true)
				.childOption(ChannelOption.SO_KEEPALIVE, false).childOption(ChannelOption.SO_LINGER, 2)
				.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
				.childHandler(new ChannelInitializer<SocketChannel>() {
					@Override
					public void initChannel(SocketChannel ch) throws Exception {
						ch.pipeline().addLast(new TransportOut(), new TransportIn(),
								// if not receive heartbeat request in 30s,close
								// channel.
								new IdleStateHandler(60, 0, 0),
								new Hamal());
					}
				});
		while (true) {
			try {
				serverBootstrap.bind(port).sync();
				break;
			} catch (InterruptedException ex) {
				Thread.currentThread().interrupt();
			} catch (Exception ex) {
				if (ex instanceof BindException) {
					port++;
				}
			}
		}
		logger.info("Transport channel init succ... port is " + port);
		return new ProviderInfo(schemal, NetUtils.getLocalHost(), port);
	}

	public void destroy() {
		bossGroup.shutdownGracefully();
		workerGroup.shutdownGracefully();
	}
}
